package top.hkyzf.study.j2se.juc.locks;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author zhufeng
 * @version 1.0
 * @date 2021-8-19 20:49
 */
public class SyncAndReentrantLockDemo2 {


    public static void main(String[] args) throws InterruptedException {

        Resource resource = new Resource();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    resource.incresementA();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    resource.decreaseB();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    resource.incresementC();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "C").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    resource.decreaseD();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "D").start();

    }


    //资源类
    static class Resource {

        //定义一个可重入锁
        Lock lock = new ReentrantLock();

        Condition conditionA = lock.newCondition();
        Condition conditionB = lock.newCondition();
        Condition conditionC = lock.newCondition();
        Condition conditionD = lock.newCondition();

        //生产资源，生产者对其加1，消费者对其减1
        private int num = 0;

        public void incresementA() throws InterruptedException {

            lock.lock();
            try {
                //对增加进行判断
                while (num > 0) {
                    conditionA.await();
                }
                num++;
                System.out.println(Thread.currentThread().getName() + "->" + num);
                //通知其他线程对其操作
                conditionB.signal();

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }

        public void decreaseB() throws InterruptedException {

            lock.lock();
            try {
                //对减少进行判断
                while (num == 0) {
                    conditionB.await();
                }
                num--;
                System.out.println(Thread.currentThread().getName() + "->" + num);
                //通知其他线程对其操作
                conditionC.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            };
        }

        public void incresementC() throws InterruptedException {

            lock.lock();
            try {
                //对增加进行判断
                while (num > 0) {
                    conditionC.await();
                }
                num++;
                System.out.println(Thread.currentThread().getName() + "->" + num);
                //通知其他线程对其操作
                conditionD.signal();

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }

        public void decreaseD() throws InterruptedException {

            lock.lock();
            try {
                //对减少进行判断
                while (num == 0) {
                    conditionD.await();
                }
                num--;
                System.out.println(Thread.currentThread().getName() + "->" + num);
                //通知其他线程对其操作
                conditionA.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            };
        }
    }

}

